﻿using System;
using System.Net;
using System.Net.Sockets;
using System.Text;
using FatCatSniffer.Header;

namespace ConsoleTester
{
    internal class Program
    {
        private const int ByteDataLength = 4096;
        private static Socket _mainSocket;
        private static byte[] ByteData { get; set; }
        public static bool IsRunning { get; set; }
        private static int Port { get; set; }

        private static void Main()
        {
            try
            {
                Port = 57222;

                IPAddress address = IPAddress.Parse("192.168.2.2");

                _mainSocket = new Socket(AddressFamily.InterNetwork, SocketType.Raw, ProtocolType.IP);

                var endPoint = new IPEndPoint(address, 0);

                _mainSocket.Bind(endPoint);

                _mainSocket.SetSocketOption(SocketOptionLevel.IP, SocketOptionName.HeaderIncluded, true);

                var byTrue = new byte[] { 1, 0, 0, 0 };
                var byOut = new byte[] { 1, 0, 0, 0 };

                _mainSocket.IOControl(IOControlCode.ReceiveAll, byTrue, byOut);

                IsRunning = true;

                StartSocketRecieveThread();

                Console.WriteLine("Press any key to exit . . . .");
                Console.ReadKey(true);

                IsRunning = false;

                _mainSocket.Close();
            }
            catch (Exception ex)
            {
                Console.WriteLine("Error Message: {0}", ex.Message);
                Console.WriteLine("Stacktrace: {0}", ex.StackTrace);
            }
        }

        private static void OnRecieve(IAsyncResult result)
        {
            int numberOfBytesRecieved = _mainSocket.EndReceive(result);

            // Do something with Data
            ParseData(ByteData, numberOfBytesRecieved);

            if (IsRunning)
            {
                StartSocketRecieveThread();
            }
        }

        private static void ParseData(byte[] byteData, int numberOfReceived)
        {
            var ipHeader = new IPHeader(byteData, numberOfReceived);

            Console.WriteLine("IPHeader DestinationAddress: {0} SourceAddress: {1}", ipHeader.DestinationAddress, ipHeader.SourceAddress);

            switch (ipHeader.ProtocolType)
            {
                case Protocol.TCP:
                    {
                        var tcpHeader = new TCPHeader(ipHeader.Data, ipHeader.MessageLength);

                        //Console.WriteLine("TCP Data On Port from {1} to {2}: {0}", Encoding.UTF8.GetString(tcpHeader.Data), tcpHeader.DestinationPort, tcpHeader.SourcePort);
                        Console.WriteLine("TCP Data On Port from {1} to {2}: {0}", string.Empty, tcpHeader.DestinationPort, tcpHeader.SourcePort);

                        //if (tcpHeader.SourcePort == Port.ToString() || tcpHeader.DestinationPort == Port.ToString())
                        //{
                        //    //Console.WriteLine("TCP DestinationPort {0}", tcpHeader.DestinationPort);
                        //    //Console.WriteLine("TCP SourcePort      {0}", tcpHeader.SourcePort);
                        //}

                        break;
                    }
                case Protocol.UDP:
                    {
                        var udpHeader = new UDPHeader(ipHeader.Data, ipHeader.MessageLength);

                        //Console.WriteLine("TCP Header Data On Port from {1} to {2}: {0}", Encoding.UTF8.GetString(udpHeader.Data), udpHeader.DestinationPort, udpHeader.SourcePort);
                        Console.WriteLine("TCP Header Data On Port from {1} to {2}: {0}", string.Empty, udpHeader.DestinationPort, udpHeader.SourcePort);

                        //if (udpHeader.SourcePort == Port.ToString() || udpHeader.DestinationPort == Port.ToString())
                        //{
                            
                        //}

                        break;
                    }
                default:
                    {
                        break;
                    }
            }
        }

        private static void PrintIPAddress()
        {
            IPHostEntry hostEntry = Dns.GetHostEntry(Dns.GetHostName());

            foreach (IPAddress item in hostEntry.AddressList)
            {
                Console.WriteLine("IP Address: {0}", item);
            }
        }

        private static void StartSocketRecieveThread()
        {
            ByteData = new byte[ByteDataLength];

            _mainSocket.BeginReceive(ByteData, 0, ByteData.Length, SocketFlags.None, new AsyncCallback(OnRecieve), null);
        }
    }
}